package cn.js189.uqc.util.filter;


import cn.hutool.core.date.DateUnit;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.text.CharSequenceUtil;
import cn.hutool.crypto.SecureUtil;
import cn.hutool.json.JSONUtil;
import cn.js189.common.constants.Constants;
import cn.js189.common.constants.HttpStatus;
import cn.js189.common.domain.ReqHead;
import cn.js189.common.util.TransactionContext;
import cn.js189.common.util.exception.GlobalException;
import cn.js189.common.util.sign.DesUtils;
import cn.js189.uqc.util.EuaCacheUtil;
import cn.js189.uqc.util.MyHttpServletRequestWrapper;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import lombok.extern.slf4j.Slf4j;
import org.springframework.core.annotation.Order;

import javax.annotation.Resource;
import javax.servlet.*;
import javax.servlet.annotation.WebFilter;
import javax.servlet.http.HttpServletRequest;
import java.io.IOException;
import java.io.PrintWriter;

@Slf4j
@WebFilter(urlPatterns = "/*")
@Order(1)
public class ChannelFilter  implements Filter {
	
	@Resource
	private EuaCacheUtil euaCacheUtil;
	
	@Override
	public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws ServletException, IOException {
		log.info("进入过滤器");
		String body = this.getBody(servletRequest);
		JSONObject reqInfo = JSON.parseObject(body);
		ReqHead head = reqInfo.getObject("head", ReqHead.class);
		
		boolean auth = this.checkReqHeadAuth(servletResponse, reqInfo);
		if (auth){
			return;
		}
		// body 参数解密
		String euaKey = euaCacheUtil.getEuaEncKeyMapByChannelId(head.getChannelId());
		if(CharSequenceUtil.isNotBlank(euaKey)){
			JSONObject desBody = DesUtils.desBody(reqInfo);
			// body参数加密过
			MyHttpServletRequestWrapper myHttpServletRequestWrapper = new MyHttpServletRequestWrapper((HttpServletRequest) servletRequest);
			// 相当于赋值
			myHttpServletRequestWrapper.getBody(JSONUtil.toJsonStr(desBody));
			// 自己定义的MyHttpServletRequestWrapper
			filterChain.doFilter(myHttpServletRequestWrapper, servletResponse);
		}else{
			// body参数未加密
			filterChain.doFilter(servletRequest,servletResponse);
		}
	}
	
	/**
	 * 请求head节点信息验证
	 * @param reqInfo 请求头
	 */
	private boolean checkReqHeadAuth(ServletResponse response,JSONObject reqInfo){
		ReqHead reqHead = reqInfo.getObject("head",ReqHead.class);
		
		// 验证必输参数不能为空
		if (reqInfo.get("body") == null || reqHead == null ||
				!CharSequenceUtil.isAllNotBlank(reqHead.getAuth(),reqHead.getChannelId(), reqHead.getRequestTime(), reqHead.getTranId())) {
			unauthorizedResponse(response,"必填参数为空检查！", HttpStatus.PARAM_ERROR);
			return true;
		}
		
		if(DateUtil.between(DateUtil.parseDateTime(reqHead.getRequestTime()), DateUtil.date(), DateUnit.HOUR) > 0){
			unauthorizedResponse(response,"请求时间过期", HttpStatus.PARAM_ERROR);
			return true;
		}
		
		String result = euaCacheUtil.check(reqHead.getChannelId(),reqHead.getActionCode() ,reqHead.getAreaCode());
		if (Constants.EUA_AUTH_0001.equals(result)) {
			unauthorizedResponse(response,"渠道不再访问范围为空",HttpStatus.EUA_CHANNEL_ERROR);
			return true;
		}else  if(Constants.EUA_AUTH_0002.equals(result)){
			unauthorizedResponse(response,"actionCode不在访问范围内",HttpStatus.EUA_ACTION_CODE_ERROR);
			return true;
		}else if(Constants.EUA_AUTH_0003.equals(result)){
			unauthorizedResponse(response,"区号不在访问范围内",HttpStatus.EUA_AREA_CODE_ERROR);
			return true;
		}
		
		// 验证流水长度 等于20
		if (reqHead.getTranId().length() != 20) {
			unauthorizedResponse(response,"验证流水长度必须为20位！",HttpStatus.PARAM_ERROR);
			return true;
		}
		
		// 验证MD5签名长度 等于32
		if (reqHead.getAuth().length() != 32) {
			unauthorizedResponse(response,"签名长度长度必须为32位！",HttpStatus.PARAM_ERROR);
			return true;
		}
		
		// 验证请求时间长度 等于19
		if (reqHead.getRequestTime().length() != 19) {
			unauthorizedResponse(response,"请求时间长度必须为19位！",HttpStatus.PARAM_ERROR);
			return true;
		}
		
		// 验证渠道ID小于20
		if (reqHead.getChannelId().length() >= 20) {
			unauthorizedResponse(response,"验证渠道ID长度必须小于20位！",HttpStatus.PARAM_ERROR);
			return true;
		}
		
		//获取渠道对于的密钥
		String key= euaCacheUtil.getEuaKeyMapByChannelId(reqHead.getChannelId());
		if(CharSequenceUtil.isBlank(key)){
			unauthorizedResponse(response,"渠道密钥为空，请检查！",HttpStatus.EUA_CHANNEL_KEY_ERROR);
			return true;
		}
		
		// 验证MD5签名
		if (!reqHead.getAuth().equals(SecureUtil.md5(reqHead.getTranId() + key))) {
			unauthorizedResponse(response,"签名验证失败！",HttpStatus.AUTH_ERROR);
			return true;
		}
		return false;
	}
	
	/**
	 * 响应返回封装
	 * @param msg 消息
	 * @param code 状态码
	 */
	private void unauthorizedResponse(ServletResponse response, String msg,String code){
		JSONObject result = new JSONObject();
		JSONObject head = new JSONObject();
		head.put("msg", msg);
		head.put("status", code);
		head.put("responseId", Constants.RSP + TransactionContext.getTranId());
		head.put("responseTime", DateUtil.formatDateTime(DateUtil.date()));
		result.put("head", head);
		response.setCharacterEncoding("UTF-8");
		response.setContentType("application/json; charset=utf-8");
		try (PrintWriter writer = response.getWriter()) {
			writer.print(result);
		} catch (IOException e) {
			log.error("response error", e);
		}
	}
	

	
	/**
	 * 获取请求体
	 * @param request 请求
	 * @return 请求体
	 */
	private String getBody(ServletRequest request) {
		try {
			ServletInputStream stream = request.getInputStream();
			StringBuilder stringBuilder = new StringBuilder();
			byte[] b = new byte[1024];
			int lens = -1;
			while ((lens = stream.read(b)) > 0) {
				stringBuilder.append(new String(b, 0, lens));
			}
			return stringBuilder.toString();
		} catch (IOException e) {
			throw new GlobalException(e.getMessage());
		}
	}
	
}
